package com.baizw.cultivation.module.flowable.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baizw.cultivation.common.exception.GlobalException;
import com.baizw.cultivation.module.admin.entity.UserEntity;
import com.baizw.cultivation.util.ShiroUtil;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.BpmnAutoLayout;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.editor.language.json.converter.BpmnJsonConverter;
import org.flowable.ui.common.model.RemoteUser;
import org.flowable.ui.common.security.DefaultPrivileges;
import org.flowable.ui.common.util.XmlUtil;
import org.flowable.ui.modeler.domain.AbstractModel;
import org.flowable.ui.modeler.domain.Model;
import org.flowable.ui.modeler.repository.ModelRepository;
import org.flowable.validation.ProcessValidator;
import org.flowable.validation.ProcessValidatorFactory;
import org.flowable.validation.ValidationError;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

/**
 * Flowable工具类
 *
 * @author 剧终1204
 * @version V1.0
 * @date 2020年12月01日 16:53
 */
@Slf4j
public class FlowableUtil {
	
	/**
	 * 创建流程XML并验证有效性并保存
	 *
	 * @param inputStream 流程模型流
	 * @param created     创建人
	 * @return 校验及保存结果
	 */
	public static Model verifyAndBuilder(InputStream inputStream, String created) throws Exception {
		BpmnXMLConverter bpmnXmlConverter = new BpmnXMLConverter();
		BpmnJsonConverter bpmnJsonConverter = new BpmnJsonConverter();
		XMLInputFactory xif = XmlUtil.createSafeXmlInputFactory();
		InputStreamReader xmlIn = new InputStreamReader(inputStream, CharsetUtil.UTF_8);
		XMLStreamReader xtr = xif.createXMLStreamReader(xmlIn);
		BpmnModel bpmnModel = bpmnXmlConverter.convertToBpmnModel(xtr);
		//模板验证
		ProcessValidator validator = new ProcessValidatorFactory().createDefaultProcessValidator();
		List<ValidationError> errors = validator.validate(bpmnModel);
		if (CollUtil.isNotEmpty(errors)) {
			String errorString = CollUtil.join(errors, StrUtil.LF);
			log.error("模板验证失败，原因: {}", errorString);
			throw new GlobalException(StrUtil.format("模板验证失败，原因: {}", errorString));
		}
		String fileName = bpmnModel.getMainProcess().getName();
		if (CollUtil.isEmpty(bpmnModel.getProcesses())) {
			log.error("没有找到模型流程定义: {}", fileName);
			throw new GlobalException(StrUtil.format("没有找到模型流程定义: {}", fileName));
		}
		if (bpmnModel.getLocationMap().size() == 0) {
			BpmnAutoLayout bpmnLayout = new BpmnAutoLayout(bpmnModel);
			bpmnLayout.execute();
		}
		ObjectNode modelNode = bpmnJsonConverter.convertToJson(bpmnModel);
		org.flowable.bpmn.model.Process process = bpmnModel.getMainProcess();
		String name = process.getId();
		if (StrUtil.isNotBlank(process.getName())) {
			name = process.getName();
		}
		String description = process.getDocumentation();
		//查询是否已经存在流程模板
		Model newModel = new Model();
		ModelRepository modelRepository = SpringUtil.getBean(ModelRepository.class);
		List<Model> models = modelRepository.findByKeyAndType(process.getId(), AbstractModel.MODEL_TYPE_BPMN);
		if (CollUtil.isNotEmpty(models)) {
			Model updateModel = models.get(0);
			newModel.setId(updateModel.getId());
		}
		newModel.setName(name);
		newModel.setKey(process.getId());
		newModel.setModelType(AbstractModel.MODEL_TYPE_BPMN);
		newModel.setCreated(Calendar.getInstance().getTime());
		newModel.setCreatedBy(created);
		newModel.setDescription(description);
		newModel.setModelEditorJson(modelNode.toString());
		newModel.setLastUpdated(Calendar.getInstance().getTime());
		newModel.setLastUpdatedBy(created);
		return newModel;
	}
	
	/**
	 * 构建模型导入所需用户信息
	 *
	 * @return RemoteUser
	 */
	public static RemoteUser buildRemoteUser() {
		UserEntity userEntity = ShiroUtil.getUser();
		RemoteUser user = new RemoteUser();
		user.setId(String.valueOf(userEntity.getId()));
		user.setDisplayName(userEntity.getLoginName());
		user.setFirstName(userEntity.getLoginName());
		user.setLastName(userEntity.getLoginName());
		List<String> pris = new ArrayList<>();
		pris.add(DefaultPrivileges.ACCESS_MODELER);
		pris.add(DefaultPrivileges.ACCESS_IDM);
		pris.add(DefaultPrivileges.ACCESS_ADMIN);
		pris.add(DefaultPrivileges.ACCESS_TASK);
		pris.add(DefaultPrivileges.ACCESS_REST_API);
		user.setPrivileges(pris);
		return user;
	}
}
